package com.hcms.common.config.shiro;

import com.hcms.common.utils.StringUtil;
import com.hcms.system.dao.*;
import com.hcms.system.domain.AdminDo;
import com.hcms.system.domain.AdminRoleDo;
import com.hcms.system.domain.RoleDo;
import com.hcms.system.domain.RoleMenuDo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import javax.print.DocFlavor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private AdminDao adminDao;

    @Autowired
    private AdminRoleDao adminRoleDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private RoleMenuDao roleMenuDao;

    @Autowired
    private MenuDao menuDao;

    // 处理身份验证逻辑
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 将 authenticationToken 转换为 UsernamePasswordToken
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        // 从 token 中获取用户名
        String username = token.getUsername();

        if (username == "") {
            throw new UnknownAccountException("请填写用户名");
        }

        AdminDo adminDo = adminDao.getByUserName(username);
        if (adminDo == null || adminDo.getMarkStatus() != 0) {
            throw new UnknownAccountException("用户不存在");
        }

        // 假设数据库中的密码是经过加密的
        String encryptedPassword = encryptPassword("123456");

        // 密码校验，由 Shiro 自动完成

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                adminDo,
                adminDo.getPassword(),
                getName()
        );

        // 返回认证信息，包括用户名和密码
        return info;
    }

    // 处理授权逻辑
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        // 1、获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        AdminDo currentAdmin = (AdminDo) subject.getPrincipal();
        if (currentAdmin == null || currentAdmin.getMarkStatus() != 0) {
            throw new AuthorizationException("管理员状态不正常");
        }
        // 2、获取用户角色
        AdminRoleDo adminRole = adminRoleDao.getByAdmin(currentAdmin.getId());
        if (adminRole == null || adminRole.getMarkStatus() != 0) {
            throw new AuthorizationException("登录账户角色异常");
        }
        // 3、判断角色信息是否正常
        RoleDo roleDo = roleDao.get(adminRole.getRoleId());
        if (roleDo == null || roleDo.getMarkStatus() != 0) {
            throw new AuthorizationException("登录账户角色异常");
        }
        // 4、获取角色菜单
        List<RoleMenuDo> roleMenuDos = roleMenuDao.listByRoleId(adminRole.getRoleId())
                .stream()
                .filter(t -> t.getMarkStatus() == 0)
                .collect(Collectors.toList());
        if (roleMenuDos == null || roleMenuDos.size() == 0) {
            throw new AuthorizationException("角色未分配权限");
        }
        // 5、获取菜单授权标识
        Set<String> permsList = new HashSet<>();
        for (RoleMenuDo roleMenuDo : roleMenuDos) {
            String perms = menuDao.findPermsByMenuId(roleMenuDo.getMenuId());
            if (perms != "") {
                permsList.add(perms);
            }
        }
        if (permsList == null || permsList.size() == 0) {
            throw new AuthorizationException("没有找到授权信息");
        }

        info.setStringPermissions(permsList);

        return info;
    }

    private String encryptPassword(String password) {
        // 使用 Shiro 提供的密码加密工具
        return new Md5Hash(password).toHex();
    }
}
